package com.harmony.pilot.agent.tools;

import com.harmony.pilot.agent.model.*;
import com.harmony.pilot.common.dto.CodeContext;
import com.harmony.pilot.common.dto.RestResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

/**
 * Fuzz测试生成工具
 */
@Component
@Slf4j
public class FuzzTestGenerationTool implements AgentTool {
    
    private final RestTemplate restTemplate;
    
    @Value("${services.generation.url:http://localhost:8082}")
    private String generationServiceUrl;
    
    public FuzzTestGenerationTool(@Autowired(required = false) RestTemplate restTemplate) {
        this.restTemplate = restTemplate != null ? restTemplate : new RestTemplate();
    }
    
    @Override
    public String getName() {
        return "fuzz_test_generation";
    }
    
    @Override
    public String getDescription() {
        return "为C++代码生成libFuzzer框架的Fuzz测试";
    }
    
    @Override
    public String getParametersSchema() {
        return """
            {
              "type": "object",
              "properties": {
                "filePath": {
                  "type": "string",
                  "description": "要生成Fuzz测试的源文件路径"
                },
                "targetFunction": {
                  "type": "string",
                  "description": "目标函数名称（可选）"
                }
              },
              "required": ["filePath"]
            }
            """;
    }
    
    @Override
    public boolean canHandle(Intent intent, ConversationContext context) {
        return intent.getType() == Intent.IntentType.TEST_GENERATION &&
               intent.getAction() != null &&
               intent.getAction().contains("fuzz");
    }
    
    @Override
    public double getRelevanceScore(Intent intent, ConversationContext context) {
        if (canHandle(intent, context)) {
            return 0.9;
        }
        return 0.0;
    }
    
    @Override
    public ToolResult execute(ToolRequest request) {
        Map<String, Object> params = request.getParameters();
        if (params == null) {
            params = new HashMap<>();
        }
        
        String filePath = (String) params.get("filePath");
        String projectRoot = request.getContext().getProjectRoot();
        
        if (filePath == null || filePath.isEmpty()) {
            filePath = request.getContext().getCurrentFile();
        }
        
        if (filePath == null || filePath.isEmpty()) {
            return ToolResult.error("未指定要生成Fuzz测试的文件路径");
        }
        
        try {
            // 读取源文件
            String fullPath = filePath;
            if (projectRoot != null && !projectRoot.isEmpty()) {
                fullPath = Paths.get(projectRoot, filePath).toString();
            }
            
            if (!Files.exists(Paths.get(fullPath))) {
                return ToolResult.error("文件不存在: " + filePath);
            }
            
            String sourceCode = Files.readString(Paths.get(fullPath));
            
            // 构建生成请求
            Map<String, Object> genRequest = new HashMap<>();
            genRequest.put("type", "fuzz_test");
            
            StringBuilder prompt = new StringBuilder();
            prompt.append("请为以下C++代码生成libFuzzer框架的Fuzz测试。\n\n");
            prompt.append("源文件：").append(filePath).append("\n\n");
            prompt.append("代码内容：\n```cpp\n").append(sourceCode).append("\n```\n\n");
            
            String targetFunction = (String) params.get("targetFunction");
            if (targetFunction != null && !targetFunction.isEmpty()) {
                prompt.append("目标函数：").append(targetFunction).append("\n\n");
            }
            
            prompt.append("要求：\n");
            prompt.append("1. 使用libFuzzer框架\n");
            prompt.append("2. 生成有效的Fuzz目标函数（extern \"C\" int LLVMFuzzerTestOneInput）\n");
            prompt.append("3. 包含边界值测试和异常输入测试\n");
            prompt.append("4. 遵循OpenHarmony编码规范\n");
            prompt.append("5. 包含详细的测试注释和说明\n");
            prompt.append("6. 测试函数名格式：fuzz_源文件名\n");
            
            genRequest.put("prompt", prompt.toString());
            genRequest.put("maxLength", 2000);
            
            CodeContext codeContext = new CodeContext();
            codeContext.setFilePath(filePath);
            codeContext.setCode(sourceCode);
            codeContext.setProjectRoot(projectRoot);
            genRequest.put("context", codeContext);
            
            // 调用代码生成服务
            RestResult<String> result = restTemplate.postForObject(
                generationServiceUrl + "/generate/test",
                genRequest,
                RestResult.class
            );
            
            if (result == null || !result.isSuccess()) {
                return ToolResult.error("生成Fuzz测试失败: " + 
                    (result != null ? result.getMessage() : "服务无响应"));
            }
            
            // 生成测试文件路径
            String fuzzTestFilePath = generateFuzzTestFilePath(filePath);
            
            Map<String, Object> data = new HashMap<>();
            data.put("fuzzTestCode", result.getData());
            data.put("fuzzTestFilePath", fuzzTestFilePath);
            data.put("sourceFilePath", filePath);
            
            return ToolResult.success(
                "Fuzz测试生成成功，测试文件: " + fuzzTestFilePath,
                data
            );
        } catch (Exception e) {
            log.error("Failed to generate fuzz test", e);
            return ToolResult.error("生成Fuzz测试失败: " + e.getMessage());
        }
    }
    
    private String generateFuzzTestFilePath(String sourceFilePath) {
        // 将源文件路径转换为Fuzz测试文件路径
        // 例如: src/utils/log_util.cpp -> tests/fuzz_log_util.cpp
        String fileName = Paths.get(sourceFilePath).getFileName().toString();
        String baseName = fileName.replace(".cpp", "").replace(".h", "");
        return "tests/fuzz_" + baseName + ".cpp";
    }
}

